﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Transactions;

namespace QuanLyHocPhi.BLL
{
    using Model;

    partial class BizSinhVien
    {
        #region Danh sách cột của DataTable dùng để import dữ liệu
        //public const string Col_Checked = "Checked";
        public const string Col_TrangThai = "TrangThai";
        public const string Col_MaSinhVien = "MaSinhVien";
        public const string Col_HoDem = "HoDem";
        public const string Col_Ten = "Ten";
        public const string Col_NgaySinh = "NgaySinh";
        public const string Col_GioiTinh = "GioiTinh";
        public const string Col_GhiChu = "GhiChu";
        public const string Col_ImportThanhCong = "ImportThanhCong";
        #endregion

        #region Trạng thái của 1 dòng dữ liệu trong quá trình tiền xử lý trước khi import
        public static class ImportStatus
        {
            public const string IN_OK = "sẵn sàng";
            public const string IN_ERROR = "lỗi";
            public const string IN_ERROR_NOT_ENOUGH = "lỗi: dữ liệu không đầy đủ";
            public const string OUT_OK = "đã nạp";
            public const string OUT_ERROR_GENERAL = "lỗi: không nạp được";
            public const string OUT_ERROR_ALREADY_EXIST = "đã tồn tại";
        }

        #endregion

        #region WriteLog
        private static void WriteLog(System.IO.StreamWriter sw, string log)
        {
            if (sw == null)
                return;
            sw.WriteLine(log);
        }

        private static void WriteLog(System.IO.StreamWriter sw, string logFormat, params object[] args)
        {
            WriteLog(sw, string.Format(logFormat, args));
        }
        #endregion

        internal static int NapDuLieuSinhVien(LoaiHinhDaoTao loaiHinh, string namTuyenSinh, string tenLopGoc, DataTable dt, string logFilePath = null)
        {
            int nInsertedSinhVien = 0;
            if (dt.Columns.Contains(Col_ImportThanhCong) == false)
                dt.Columns.Add(Col_ImportThanhCong, typeof(bool));

            //using (var tc = new TransactionScope(TransactionScopeOption.Required))
            using (var context = new QLHPEntities())
            {
                #region System.IO.StreamWriter sr = mở file log nếu được
                System.IO.StreamWriter sw = null;
                if (logFilePath != null)
                    try
                    {
                        sw = new System.IO.StreamWriter(logFilePath);
                    }
                    catch
                    {
                        logFilePath = null;
                    }
                #endregion

                try
                {
                    string st = string.Format("{2} -- Nạp dữ liệu sinh viên - năm tuyển sinh {0} loại hình đào tạo {1}",
                        namTuyenSinh, loaiHinh.TenLoaiHinh, DateTime.Now.ToString("dd/MM/yyyy hh:mmLss"));
                    WriteLog(sw, st);
                    WriteLog(sw, StringUtils.TạoChuỗi('-', st.Length));

                    #region 01. Tạo lớp gốc
                    WriteLog(sw, "01. Tạo lớp gốc ", DateTime.Now.ToString("dd/MM/yyyy hh:mmLss"));
                    var oLopGoc = context.LopGocDbSet
                        .Where(e => e.TenLopGoc == tenLopGoc)
                        .FirstOrDefault();
                    if (oLopGoc == null)
                    {
                        // Lớp gốc chưa tồn tại → Tạo lớp gốc
                        oLopGoc = new LopGoc
                        {
                            MaLopGoc = Guid.NewGuid().ToString(),
                            TenLopGoc = tenLopGoc,
                            NamTuyenSinh = namTuyenSinh,
                            MaLoaiHinhDaoTao = loaiHinh.MaLoaiHinh
                        };
                        try
                        {
                            context.LopGocDbSet.Add(oLopGoc);
                            context.SaveChanges();
                            WriteLog(sw, "+LopGoc+{0}\tTạo lớp gốc {1}", oLopGoc.MaLopGoc, tenLopGoc);
                        }
                        catch (Exception exc)
                        {
                            string msg = string.Format("\tLỗi khi tạo lớp gốc {0}: {1}", tenLopGoc, exc.Message);
                            WriteLog(sw, msg);
                            throw new Exception(msg, exc);
                        }
                    }
                    else
                    {
                        #region Kiểm tra xem thử lớp gốc với tên đã tồn tại có nhất quán với dữ liệu mới hay không
                        if (oLopGoc.MaLoaiHinhDaoTao != loaiHinh.MaLoaiHinh)
                            throw new Exception(string.Format(
                                "Trong hệ thống đã tồn tại lớp [{0}] không thuộc loại hình đào tạo [{1}]\n\n" +
                                "Cách khắc phục: \n" +
                                "  (1) Xoá lớp [{0}] rồi quay trở lại nạp dữ liệu, hoặc\n" +
                                "  (2) Chọn loại hình đào tạo [{2}] để nạp dữ liệu",
                                oLopGoc.TenLopGoc, loaiHinh.TenLoaiHinh, oLopGoc.LoaiHinhDaoTao.TenLoaiHinh));
                        if (oLopGoc.NamTuyenSinh != namTuyenSinh)
                            throw new Exception(string.Format("Trong hệ thống đã tồn tại lớp [{0}] với năm tuyển sinh là [{1}]\n\n" +
                                "Cách khắc phục: \n" +
                                "  (1) Xoá lớp [{0}] rồi quay trở lại nạp dữ liệu, hoặc\n" +
                                "  (2) Chọn năm tuyển sinh [{1}] để nạp dữ liệu",
                                oLopGoc.TenLopGoc, oLopGoc.NamTuyenSinh));
                        #endregion
                    }
                    #endregion

                    #region 02. Đăng ký thông tin sinh viên
                    WriteLog(sw, "02. Đăng ký dữ liệu sinh viên");
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        DataRow row = dt.Rows[i];

                        var trangThai = Convert.ToString(row[Col_TrangThai]);

                        // omit the row that is not ready to import.
                        if (trangThai.Equals(ImportStatus.IN_OK) == false)
                            continue;

                        // also omit the row that are successfully imported
                        if (trangThai.Equals(ImportStatus.OUT_OK))
                            continue;

                        string maSinhVien = Convert.ToString(row[Col_MaSinhVien]);
                        if (maSinhVien.IsNullOrEmpty())
                            continue;

                        int countSinhVien = context.SinhVienDbSet.Where(e => e.MaSinhVien == maSinhVien).Count();
                        if (countSinhVien != 0)
                        {
                            row[Col_TrangThai] = ImportStatus.OUT_ERROR_ALREADY_EXIST;
                            continue;
                        }

                        #region Nạp sinh viên vào hệ thống
                        string maLopGoc = oLopGoc.MaLopGoc;
                        string hoDem = Convert.ToString(row[Col_HoDem]);
                        #region string ten;
                        string ten = "";
                        try
                        {
                            ten = Convert.ToString(row[Col_Ten]);
                        }
                        catch { ten = ""; }
                        #endregion
                        #region string ngaySinh;
                        string ngaySinh = "";
                        try
                        {
                            ngaySinh = Convert.ToString(row[Col_NgaySinh]);
                        }
                        catch
                        {
                            ngaySinh = "";
                        }
                        #endregion
                        #region bool gioiTinh;
                        bool gioiTinh = true;
                        try
                        {
                            gioiTinh = Convert.ToBoolean(row[Col_GioiTinh]);
                        }
                        catch
                        {
                            gioiTinh = true;
                        }
                        #endregion
                        string ghiChu = "";

                        #region var oSinhVien = new SinhVien{};
                        var oSinhVien = new SinhVien
                                        {
                                            MaSinhVien = maSinhVien,
                                            HoDem = hoDem,
                                            Ten = ten,
                                            GioiTinh = gioiTinh,
                                            NgaySinh = ngaySinh,
                                            GhiChu = ghiChu,
                                            MaLopGoc = oLopGoc.MaLopGoc
                                        };
                        #endregion

                        #region try to add oSinhVien
                        try
                        {
                            context.SinhVienDbSet.Add(oSinhVien);
                            context.SaveChanges();
                            WriteLog(sw, "+SinhVien+{0}\tTạo record sinh viên {0} {1} giới tính={2}, ngày sinh = {3}",
                                maSinhVien, hoDem, ten, gioiTinh, ngaySinh, ghiChu);
                            row[Col_TrangThai] = ImportStatus.OUT_OK;
                            nInsertedSinhVien++;
                        }
                        catch (Exception exc)
                        {
                            string msg = string.Format("\tLỗi khi tạo record sinh viên {0}-{1}: {2}", maSinhVien, hoDem + " " + ten, exc.Message);
                            WriteLog(sw, msg);
                            //throw new Exception(msg, exc);
                            row[Col_TrangThai] = ImportStatus.OUT_ERROR_GENERAL;
                        }
                        #endregion
                        #endregion
                    }
                    #endregion

                    //tc.Complete();
                }
                catch (Exception exc)
                {
                    throw exc;
                }
                finally
                {
                    if (sw != null)
                        sw.Close();
                }
                return nInsertedSinhVien;
            }
        }

        internal static string UndoNapDuLieuSinhVien(string logfile)
        {
            System.IO.StreamReader sr = null;
            using (var context = new QLHPEntities())
            {
                try
                {
                    #region Đọc và phân tích các task
                    sr = new System.IO.StreamReader(logfile);
                    List<string> lstTask = new List<string>();
                    while (true)
                    {
                        string line = sr.ReadLine();
                        if (line == null)
                            break;
                        if (line.StartsWith("+") == false)
                            continue;
                        int idxTab = line.IndexOf("\t");
                        if (idxTab <= 0)
                            continue;
                        line = line.Substring(1, idxTab - 1);
                        if (line.Length > 0)
                            lstTask.Add(line);
                    }
                    #endregion

                    #region Thực hiện undo các task
                    List<string> lstUndo = new List<string>();
                    int nUndo_OK = 0;
                    for (int i = lstTask.Count - 1; i >= 0; i--)
                    {
                        string task = lstTask[i];
                        string[] param = task.Split('+');
                        if (param.Length == 0)
                            continue;
                        string stCommand = "";
                        if (param[0] == "LopGoc")
                        {
                            #region Xoá lớp gốc
                            stCommand = string.Format("delete from LopGoc where MaLop='{0}'", param[1]);
                            #endregion
                        }
                        else if (param[0] == "SinhVien")
                        {
                            #region Xoá sinh viên
                            stCommand = string.Format("delete from SinhVien where MaSinhVien='{0}'", param[1]);
                            #endregion
                        }
                        try
                        {
                            int nEffected = context.Database.ExecuteSqlCommand(stCommand);
                            if (nEffected > 0)
                            {
                                lstUndo.Add(string.Format("-{0}", task));
                                nUndo_OK++;
                            }
                            else
                                lstUndo.Add(string.Format("~{0}", task));
                        }
                        catch (Exception exc)
                        {
                            lstUndo.Add(string.Format("!{0}!{1}!{2}", task, stCommand, exc.Message));
                        }
                    }
                    #endregion

                    #region Ghi file undo task
                    var undoFileName = string.Format("{0}@{1}.undo",
                        System.IO.Path.GetFileNameWithoutExtension(logfile),
                        DateTime.Now.ToString("yyyyMMdd-HHmm"));
                    var undoDir = new System.IO.FileInfo(logfile).Directory.FullName;
                    var undoFullFilePath = System.IO.Path.Combine(undoDir, undoFileName);
                    var sw = new System.IO.StreamWriter(undoFullFilePath);
                    for (int i = lstUndo.Count - 1; i >= 0; i--)
                        sw.WriteLine(lstUndo[i]);
                    sw.Close();
                    return string.Format(
                        "Khôi phục được {0}/{1} thao tác!\n" +
                        "Xem chi tiết tại file {2}", nUndo_OK, lstTask.Count, undoFileName);
                    #endregion
                }
                catch (Exception exc)
                {
                    return "Lỗi " + exc.Message;
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }
        }

        internal static List<SinhVien> GetListSinhVien(string maLop)
        {
            using (var context = new QLHPEntities())
            {
                return context.SinhVienDbSet.Where(e => e.MaLopGoc == maLop).ToList();
            }
        }

        internal static void AddSinhVien(SinhVien sv)
        {
            using (var context = new QLHPEntities())
            {
                var oSinhVien = context.SinhVienDbSet.Where(e => e.MaSinhVien == sv.MaSinhVien).FirstOrDefault();
                if (oSinhVien != null)
                    throw new Exception(string.Format("Đã tồn tại sinh viên [{0}] {1} trên hệ thống",
                        oSinhVien.MaSinhVien, oSinhVien.HoDem + " " + oSinhVien.Ten));
                context.SinhVienDbSet.Add(sv);
                context.SaveChanges();
            }
        }

        internal static void UpdateSinhVien(SinhVien sv)
        {
            using (var context = new QLHPEntities())
            {
                var oSinhVien = context.SinhVienDbSet.Where(e => e.MaSinhVien == sv.MaSinhVien).FirstOrDefault();
                if (oSinhVien == null)
                    throw new Exception("Sinh viên cần cập nhật không còn tồn tại trên hệ thống");
                oSinhVien.HoDem = sv.HoDem;
                oSinhVien.Ten = sv.Ten;
                oSinhVien.GioiTinh = sv.GioiTinh;
                oSinhVien.NgaySinh = sv.NgaySinh;
                oSinhVien.MaLopGoc = sv.MaLopGoc;
                context.SaveChanges();
            }
        }

        internal static void DeleteSinhVien(SinhVien sv)
        {
            using (var context = new QLHPEntities())
            {
                var oSinhVien = context.SinhVienDbSet.Where(e => e.MaSinhVien == sv.MaSinhVien).FirstOrDefault();
                if (oSinhVien == null)
                    throw new Exception("Sinh viên cần xoá không còn tồn tại trên hệ thống");
                context.SinhVienDbSet.Remove(oSinhVien);
                context.SaveChanges();
            }
        }
    }
}
